﻿//-----------------------------------------------------------------------------------
// <copyright file="UnitTestMethodInvokerTest.cs" company="P.O.S Informatique">
//     Copyright (c) P.O.S Informatique. All rights reserved.
// </copyright>
//-----------------------------------------------------------------------------------
namespace PosInformatique.DevelopmentTools.VisualStudio.TestExtensions.Tests
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    using PosInformatique.Framework;

    [TestClass]
    public class UnitTestMethodInvokerTest
    {
        [TestMethod]
        public void InvokeTest()
        {
            UnitTestMethodInvokerInfo info;
            info = new UnitTestMethodInvokerInfo(typeof(ClassWithTestMethods).GetMethod("MethodToInvoke"));

            UnitTestMethodInvoker invoker;
            invoker = new UnitTestMethodInvoker(info);

            // Check if the ClassWithTestMethods has been instantiate
            Assert.IsNotNull(ClassWithTestMethods.Instance);

            UnitTestMethodInvokerResult result;
            result = invoker.Invoke();

            invoker.Dispose();

            // Check if the method has been invoked
            Assert.IsTrue(ClassWithTestMethods.Instance.MethodInvoked);

            // And no exception in the result of the invoke method
            Assert.IsNull(result.Exception);
        }

        [TestMethod]
        public void Invoke_OccursException_Test()
        {
            UnitTestMethodInvokerInfo info;
            info = new UnitTestMethodInvokerInfo(typeof(ClassWithTestMethodsWhichOccursException).GetMethod("MethodToInvoke"));

            UnitTestMethodInvoker invoker;
            invoker = new UnitTestMethodInvoker(info);

            // Check if the ClassWithTestMethods has been instantiate
            Assert.IsNotNull(ClassWithTestMethodsWhichOccursException.Instance);

            // Call the Invoke() method
            Exception exception;
            exception = new Exception("Foobar");

            ClassWithTestMethodsWhichOccursException.Instance.Exception = exception;

            UnitTestMethodInvokerResult result;
            result = invoker.Invoke();

            // Check if the method has been invoked
            Assert.IsTrue(ClassWithTestMethodsWhichOccursException.Instance.MethodInvoked);

            // And no exception in the result of the invoke method
            Assert.AreSame(exception, result.Exception);
        }

        [TestMethod]
        public void Dispose_Test()
        {
            UnitTestMethodInvokerInfo info;
            info = new UnitTestMethodInvokerInfo(typeof(ClassForDisposeTest).GetMethod("MethodToInvoke"));

            UnitTestMethodInvoker invoker;
            invoker = new UnitTestMethodInvoker(info);

            // Check if the ClassWithTestMethods has been instantiate
            Assert.IsNotNull(ClassForDisposeTest.Instance);

            // Dispose the class
            invoker.Dispose();

            // Check if the Dispose() method has been invoked
            Assert.IsTrue(ClassForDisposeTest.Instance.IsDisposed);
        }

        private class ClassWithTestMethods
        {
            public ClassWithTestMethods()
            {
                Assert.IsNull(Instance, "The ClassWithTestMethods has already been instantiated");

                Instance = this;
            }

            public static ClassWithTestMethods Instance
            {
                get;
                private set;
            }

            public bool MethodInvoked
            {
                get;
                set;
            }

            public void MethodToInvoke()
            {
                this.MethodInvoked = true;
            }
        }

        private class ClassWithTestMethodsWhichOccursException
        {
            public ClassWithTestMethodsWhichOccursException()
            {
                Assert.IsNull(Instance, "The ClassWithTestMethodsWhichOccursException has already been instantiated");

                Instance = this;
            }

            public static ClassWithTestMethodsWhichOccursException Instance
            {
                get;
                private set;
            }
            
            public bool MethodInvoked
            {
                get;
                private set;
            }

            public Exception Exception
            {
                get;
                set;
            }

            public void MethodToInvoke()
            {
                this.MethodInvoked = true;

                throw this.Exception;
            }
        }

        private class ClassForDisposeTest : IDisposable
        {
            public ClassForDisposeTest()
            {
                Assert.IsNull(Instance, "The ClassForDisposeTest has already been instantiated");

                Instance = this;
            }

            public static ClassForDisposeTest Instance
            {
                get;
                private set;
            }

            public bool IsDisposed
            {
                get;
                private set;
            }

            public void MethodToInvoke()
            {
            }

            public void Dispose()
            {
                this.IsDisposed = true;
            }
        }
    }
}
